<?php
/**
 * @link https://www.len168.com
 * @copyright Copyright (c) 2020/9/16 len168.com
 * @author toshcn <toshcn@foxmail.com>
 */

namespace common\components;

use Yii;
use yii\base\BaseObject;

class Config extends BaseObject
{
    const CONFIG_TYPE_SITE = 'site';// 配置分类
    const CONFIG_TYPE_USER = 'user';// 配置分类

    /** @var string 数据库组件 */
    public $db = 'db';
    /** @var string 缓存组件 */
    public $cache = 'cache';

    private $secretKey = 'video_len168@foxmail.com';//加密密钥

    /**
     * @var string 配置表.
     */
    public $table = '{{%config}}';

    /** @var array 站点配置数组 */
    private $_siteArr = [
        'siteName' => '任务平台', // 网站名称
        'siteHost' => '网站H5访问域名', // 网站H5访问域名
        'inviteHost' => '', // 邀请注册域名
        'siteDescription' => '', // 网站描述
        'siteStatus' => 1, // 网站状态：1开启，0关闭
        'siteCloseReason' => '', // 网站状态原因
        'defaultPageSize' => 10, // 默认分页数
        'adminEmail' => 'admin@example.com', // 管理员邮箱
        'supportEmail' => 'support@example.com', // 技术支持邮箱
        'senderEmail' => 'noreply@example.com', // 发送邮箱
        'senderEmailName' => 'Example.com mailer', // 发送邮箱名称
        'captchaCaseSensitive' => false, // 本地验证码大小写是否敏感
        'registerNeedVerify' => true, // 用户注册是否需要审核
        'smsHandler' => 'aliyunSms', // 短信处理器
        'aliyunSms' => [
            'key' => '',// 阿里云短信服务Key
            'secret' => '', // 阿里云短信服务Secret
        ],
        'imgCaptchaLength' => 6, //图形验证码长度
        'smsCaptchaLength' => 6, //短信验证码长度
        'smsCaptchaDuration' => 600, //短信验证码有效时长秒
        'userRegisterOnValidateCaptcha' => true, // 用户注册是否开启验证码验证
        'imgCaptcha' => [
            'imageLibrary' => 'imagick',
            'foreColor' => 'auto',// 图形验证码颜色16进制值如：白色FFFFFF, 自动auto
            'width' => 120,//图形验证码图片宽度
            'offset' => -1,//图形验证码字符间隔
            'padding' => 0,//图形验证码字符内边距
            'minFontSize' => 22,//图形验证码字体最小
            'maxFontSize' => 26,//图形验证码字体最大
            'cacheDuration' => 600,//有效时长秒
            'isWriteCurve' => 1,//图形验证码干扰线 1开启 0关闭
            'isWriteNoise' => 1,//图形验证码干扰字符 1开启 0关闭
            'disturbCharCount' => 4,//图形验证码干扰字符数量
            'noiseMinFontSize' => 12,//干扰字符字体最小
            'noiseMaxFontSize' => 24,//干扰字符字体最大
        ],
        'ossHandler' => 'localOss', // OSS上传文件服务
        'localOss' => [
            'host' => 'http://pic.example.com' // 本地OSS访问域名
        ],
        'aliyunOss' => [
            'secretId' => '', // 阿里云OSS服务ID
            'secretKey' => '', // 阿里云OSS服务KEY
            'endpoint' => '', // 阿里云储存域
            'bucket' => '', // 阿里云Bucket名称
            'selfHost' => '' // 阿里云OSS自定义访问域名
        ],
        'qcloudOss' => [
            'secretId' => '', // 腾讯云OSS服务ID
            'secretKey' => '', // 腾讯云OSS服务KEY
            'region' => '', // 腾讯云储存域
            'bucket' => '' // 腾讯云Bucket名称
        ],
        'uploadFileMaxSize' => 10, // 允许上传的文件大小MB
        'uploadFileExt' => ['jpg', 'jpeg', 'png', 'gif', 'webp', 'mp4', 'mov', 'webm', 'mp3', 'wma'], // 允许上传的文件类型
        'uploadImageMaxSize' => 2, // 允许上传的图片大小MB
        'uploadImageExt' => ['jpg', 'jpeg', 'png', 'gif', 'webp'], // 允许上传的图片类型
        'uploadVideoMaxSize' => 10, // 允许上传的视频大小MB
        'uploadVideoExt' => ['mp4', 'mov', 'webm'], // 允许上传的视频类型
        'uploadAudioMaxSize' => 2, // 允许上传的音频大小MB
        'uploadAudioExt' => ['mp3', 'wma'], // 允许上传的音频类型
        'alipayOauth' => [
            'use' => 1, //支付宝授权开启1 关闭0
            'appId' => '', //支付宝appId
            'pid' => '', // 支付宝商户号以 2088 开头的 16 位纯数字组成,示例：2088123456789012
            'merchantPrivateKey' => '', //应用私钥
            'alipayPublicKey' => '', //支付宝公钥
            'redirectUri' => '', //网页授权回调地址
            'encryptKey' => '', //调用AES加解密相关接口时需要
        ],
        'weixinOauth' => [
            'use' => 1, // 微信授权开启1 关闭0
            'appId' => '', // 微信appId
            'secret' => '', // 微信应用私钥
        ],
        'alipay' => [
            'use' => 1, //支付宝开启1 关闭0
            'appId' => '', //支付宝appId
            'merchantPrivateKey' => '', //应用私钥
            'alipayPublicKey' => '', //支付宝公钥
            'notifyUrl' => '', //异步通知接收服务地址
            'encryptKey' => '', //调用AES加解密相关接口时需要
        ],
        'wxpay' => [
            'use' => 0, //微信支付开启1 关闭0
            'appId' => '', //微信支付appId
            'mchId' => '', //微信商户id
            'key' => '', //微信商户key
            'notifyUrl' => '', //异步通知接收服务地址
        ],
        'articles' => [
            'aboutUs' => 0, //关于我们 对应的帮助中心文章ID
            'userServiceAgreement' => 0, //用户协议 对应的帮助中心文章ID
            'privacyPolicy' => 0 // 隐私政策 对应的帮助中心文章ID
        ],
        'appVersion' => '1.0.0', //当前app版本号
        'appVersionNum' => '100', //当前APP版本号值
        'appResVersionNum' => '100', //当前APP资源包版本号值
        'appAndroidUpLink' => '', //app更新链接
        'appiOSUpLink' => '', //app更新链接
        'appAndroidResUpLink' => '', //app 安卓资源包更新链接
        'appiOSResUpLink' => '', //app ios资源包更新链接
        'appStoreDownLink' => '', //应用商店下载链接
        'appAndroidUpInfo' => '', //app安卓版本更新说明
        'appiOSUpInfo' => '', //app ios版本更新说明
    ];
    /** @var array 用户相关配置 */
    private $_userArr = [
        'registerNeedVerify' => 0, // 注册审核 1开启 0关闭
        'loginPasswordError' => 5, // 登录密码输入错误次数超过此值, 会提示用户稍后再试, 0不限制.
        'userPasswordResetTokenExpire' => 600, // 重置密码token有效时长(秒)
        'userLoginAccessTokenExpire' => 604800, // 保持登录时长(秒) 默认7 * 24 * 3600
        // 邀请注册链接有效时间(天) 0不限
        'inviteRegisterUrlInterval' => 7,
        // 同一个ip邀请注册间隔秒
        'inviteRegisterIpInterval' => 61,
        // 同一IP每天可邀请注册数量
        'inviteRegisterIpDayLimit' => 3,
        // 同一账号每天可邀请注册数量, 0不限
        'inviteRegisterDayLimit' => 100,
    ];

    /**
     * 初始化
     */
    public function init()
    {
        parent::init();
        $db = $this->db;
        $this->db = Yii::$app->$db;

        $cache = $this->cache;
        $this->cache = Yii::$app->$cache;
    }

    /**
     * 初始化数据
     */
    public function initConfigTable()
    {
        $this->_configInit(static::CONFIG_TYPE_SITE);
        $this->_configInit(static::CONFIG_TYPE_USER);
        return false;
    }

    /**
     * 缓存键值
     * @param string $name 配置类型
     * @return string
     */
    public static function cacheKey($name)
    {
        return '__' . strtoupper($name) . '_CONFIG_CATCH__';
    }

    /**
     * 初始化配置
     * @param string $name 配置分类
     * @param array $data 配置值
     * @return mixed
     */
    private function _configInit($name, $data = [])
    {
        $arr = "_{$name}Arr";

        $data = array_merge($this->$arr, $data);
        $key = static::cacheKey($name);
        $json = $this->encrypt(json_encode($data, JSON_UNESCAPED_UNICODE));
        $this->cache->set(Yii::$app->util->cacheKey($key), $json);
        return $this->db->createCommand()->upsert($this->table, [
            'name' => $name,
            'config_json' => $json,
            'updated_at' => date('Y-m-d H:i:s'),
            'created_at' => date('Y-m-d H:i:s'),
        ], [
            'config_json' => $json,
            'updated_at' => date('Y-m-d H:i:s')
        ])->execute();
    }

    /**
     * 获取库中配置项全部配置
     * @param string $type 配置项名称
     * @return mixed
     */
    public function getDbConfig($type)
    {
        // 读库
        if ($config = $this->db->createCommand("SELECT * FROM {$this->table} WHERE `name`=:type")
            ->bindValue(':type', $type)
            ->queryOne()) {
            $json = json_decode($this->decrypt($config['config_json']), true);
            return $json;
        }
        $arr = "_{$type}Arr";
        return $this->$arr;
    }

    /**
     * 站点配置项 兼容接口
     * @param $name string 配置项名称
     * @param string $default
     * @return null
     */
    public function getNormalItem($name, $default = NULL)
    {
        return $this->getSiteItem($name, $default);
    }

    /**
     * 站点配置项 兼容接口
     * @param $name string 配置项名称
     * @param string $default
     * @return null
     */
    public function getItem($name, $default = NULL)
    {
        return $this->getSiteItem($name, $default);
    }

    /**
     * 站点配置项
     * @param $name string 配置项名称
     * @param string $default
     * @return null
     */
    public function getSiteItem($name, $default = NULL)
    {
        return $this->_item($name, static::CONFIG_TYPE_SITE, $default);
    }

    /**
     * 用户配置项
     * @param $name string 配置项名称
     * @param string $default
     * @return null
     */
    public function getUserItem($name, $default = NULL)
    {
        return $this->_item($name, static::CONFIG_TYPE_USER, $default);
    }

    /**
     * 获取全部用户配置
     */
    public function getUserItems()
    {
        return $this->_getAllItems('user');
    }

    /**
     * 获取全部配置
     * @param $type string 配置类型
     * @return array|mixed
     */
    private function _getAllItems($type)
    {
        // 读取缓存中配置
        $key = static::cacheKey($type);
        $json = $this->cache->get(Yii::$app->util->cacheKey($key));
        if ($json === false) {
            // 读库
            $json = $this->getDbConfig($type);
            // 加密缓存
            $this->cache->set(Yii::$app->util->cacheKey($key), $this->encrypt(json_encode($json, JSON_UNESCAPED_UNICODE)));
        } else {
            // 解密缓存
            $json = json_decode($this->decrypt($json), true);
        }

        if (!empty($json)) {
            return (array) $json;
        }

        // 返回默认配置
        $arr = "_{$type}Arr";
        return $this->$arr;
    }

    /**
     * 获取配置
     * @param string $name 配置项
     * @param null $default 默认值
     * @param string $type 配置分类
     * @return mixed|string
     */
    private function _item($name, $type, $default = NULL)
    {
        // 读取缓存中配置
        $key = static::cacheKey($type);
        $json = $this->cache->get(Yii::$app->util->cacheKey($key));
        if ($json === false) {
            // 读库
            $json = $this->getDbConfig($type);
            // 加密缓存
            $this->cache->set(Yii::$app->util->cacheKey($key), $this->encrypt(json_encode($json, JSON_UNESCAPED_UNICODE)));
        } else {
            // 解密缓存
            $json = json_decode($this->decrypt($json), true);
        }

        if (isset($json[$name])) {
            return $json[$name];
        }

        // 返回默认配置
        $arr = "_{$type}Arr";
        $defaultArr = $this->$arr;
        if ($default === NULL && isset($defaultArr[$name])) {
            return $defaultArr[$name];
        }

        return '';
    }

    /**
     * 保存配置到数据库
     * @param array $data 配置数组
     * @param $name string 配置类型
     * @return bool
     */
    public function setConfigRecord($data, $name)
    {
        $config = $this->db->createCommand("SELECT * FROM {$this->table} WHERE `name`=:name")
            ->bindValues([':name' => $name])
            ->queryOne();
        if ($config) {
            $json = json_decode($this->decrypt($config['config_json']), true);
            // 合并配置
            $json = array_merge($json, $data);
            // 加密
            $json = $this->encrypt(json_encode($json, JSON_UNESCAPED_UNICODE));
            if ($this->db->createCommand()
                ->update($this->table, ['config_json' => $json, 'updated_at' => date('Y-m-d H:i:s')], ['id' => $config['id']])
                ->execute()) {

                $key = static::cacheKey($name);
                $this->cache->set(Yii::$app->util->cacheKey($key), $json);
                return true;
            }
        } else {
            // 初始化
            return $this->_configInit($name, $data);
        }

        return false;
    }

    /**
     * 加密
     * @param string $data 解密数据
     * @return mixed
     */
    public function encrypt($data)
    {
        return base64_encode(Yii::$app->getSecurity()->encryptByKey($data, $this->secretKey));
    }

    /**
     * 解密
     * @param string $data 解密数据
     * @return mixed
     */
    public function decrypt($data)
    {
        return Yii::$app->getSecurity()->decryptByKey(base64_decode($data), $this->secretKey);
    }
}
